/**
 * Copyright 2021 xpstem.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.xpstem.lelink.connection;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.xpstem.lelink.bluetooth.BluetoothConnection;
import com.xpstem.lelink.util.ByteUtil;
import com.xpstem.lelink.util.StrUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Optional;

/**
 * @author billy zhang
 */
public class BrickConnection extends BaseConnection {

    public static final String TAG = BrickConnection.class.getSimpleName();

    private Context context;
    private String macAddress;
    private BluetoothConnection bleConnection;
    private Optional<BluetoothConnection.OnConnectListener> connectListener = Optional.empty();
    private ByteBuffer byteBuf = ByteBuffer.allocate(65536);

    public BrickConnection(Context context) {
        this.context = context;
    }

    public void setBtAddress(String macAddress) {
        this.macAddress = macAddress;
    }

    public void setOnConnectListener(BluetoothConnection.OnConnectListener listener) {
        connectListener = Optional.ofNullable(listener);
    }

    @Override
    protected int doConnect() throws IOException {

        bleConnection = new BluetoothConnection(context, macAddress);
        bleConnection.setOnConnectListener(new BluetoothConnection.OnConnectListener() {
            @Override
            public void onConnectSuccess() {
                connectListener.ifPresent(l->l.onConnectSuccess());
            }

            @Override
            public void onConnectFailed() {
                connectListener.ifPresent(l->l.onConnectFailed());
            }

            @Override
            public void onConnectionLost(Exception ex) {
                connectListener.ifPresent(l->l.onConnectionLost(ex));
                reconnect();
            }
        });
        bleConnection.setOnChannelListener(new BluetoothConnection.OnChannelListener() {
            @Override
            public void onSend(byte[] data) {
                Log.i(TAG,"send data: " + StrUtil.toHexWithSep(data, "_"));
            }

            @Override
            public void onReceive(byte[] data) {

                Log.i(TAG,"receive data: " + StrUtil.toHexWithSep(data, "_"));

                byteBuf.put(data);

                byteBuf.flip();
                if (byteBuf.limit() < 2) {
                    // wait more data.
                    return;
                }

                byte b0 = byteBuf.get();
                byte b1 = byteBuf.get();
                int pkgLen = (int)b0 + ((int)b1 << 8) + 2;
                if (byteBuf.limit() < pkgLen) {
                    Log.i(TAG, "wait more data, package length:" + pkgLen + ", limit=" + byteBuf.limit());
                    return;
                }

                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                int msgLen = pkgLen -2;
                while (msgLen > 0) {
                    outStream.write(byteBuf.get());
                    msgLen--;
                }

                if (msgHandler != null) {
                    Message message = msgHandler.obtainMessage();
                    message.what = 1;
                    message.obj = outStream.toByteArray();
                    msgHandler.sendMessage(message);
                }

                byteBuf.compact();
            }

            @Override
            public void onError(Exception ex) {

            }
        });
        bleConnection.connect();

        return 0;
    }

    private void reconnect() {
//        try {
//            doConnect();
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
    }

    @Override
    protected void doSend(byte[] data) throws IOException {

        bleConnection.send(data);

    }

    @Override
    public void disconnect() throws IOException {
        bleConnection.disconnect();
    }

    Handler msgHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            byte[] data = (byte[])msg.obj;
            int counter = ByteUtil.byteToInt(data[0]) + (ByteUtil.byteToInt(data[1]) << 8);
            Log.i(TAG, "handle message, counter=" + counter + ",mesage:" + StrUtil.toHexWithSep(data, "_"));
            response(counter, data);
        }
    };

}
